package com.odyssey.main;

import com.odyssey.common.*;
import com.odyssey.enemies.*;
import com.odyssey.player.*;

import org.anddev.andengine.engine.Engine;
import org.anddev.andengine.engine.camera.BoundCamera;
import org.anddev.andengine.engine.handler.IUpdateHandler;
import org.anddev.andengine.engine.options.EngineOptions;
import org.anddev.andengine.engine.options.EngineOptions.ScreenOrientation;
import org.anddev.andengine.engine.options.resolutionpolicy.RatioResolutionPolicy;
import org.anddev.andengine.entity.layer.tiled.tmx.TMXLayer;
import org.anddev.andengine.entity.layer.tiled.tmx.TMXLoader;
import org.anddev.andengine.entity.layer.tiled.tmx.TMXLoader.ITMXTilePropertiesListener;
import org.anddev.andengine.entity.layer.tiled.tmx.TMXProperties;
import org.anddev.andengine.entity.layer.tiled.tmx.TMXTile;
import org.anddev.andengine.entity.layer.tiled.tmx.TMXTileProperty;
import org.anddev.andengine.entity.layer.tiled.tmx.TMXTiledMap;
import org.anddev.andengine.entity.layer.tiled.tmx.util.exception.TMXLoadException;
import org.anddev.andengine.entity.scene.Scene;
import org.anddev.andengine.entity.scene.Scene.IOnSceneTouchListener;
import org.anddev.andengine.entity.scene.background.ColorBackground;
import org.anddev.andengine.entity.sprite.AnimatedSprite;
//import org.anddev.andengine.entity.sprite.TiledSprite;
import org.anddev.andengine.entity.util.FPSLogger;
import org.anddev.andengine.input.touch.TouchEvent;
//import org.anddev.andengine.opengl.texture.Texture;
import org.anddev.andengine.opengl.texture.TextureOptions;
import org.anddev.andengine.audio.music.Music;
import org.anddev.andengine.audio.music.MusicFactory;
import org.anddev.andengine.audio.sound.Sound;
import org.anddev.andengine.audio.sound.SoundFactory;
import org.anddev.andengine.opengl.texture.atlas.bitmap.BitmapTextureAtlas;
import org.anddev.andengine.opengl.texture.atlas.bitmap.BitmapTextureAtlasTextureRegionFactory;
import org.anddev.andengine.opengl.texture.region.TiledTextureRegion;
import org.anddev.andengine.sensor.accelerometer.AccelerometerData;
import org.anddev.andengine.sensor.accelerometer.IAccelerometerListener;
import org.anddev.andengine.ui.activity.BaseGameActivity;
import org.anddev.andengine.util.Debug;

import java.io.IOException;
import java.util.Vector;

import android.content.Intent;
import android.util.Log;


public class SampleGameActivity extends BaseGameActivity implements IAccelerometerListener, IOnSceneTouchListener{

  //BitmapTextureAtlases
  private BitmapTextureAtlas mBitmapTextureAtlas;
  private BitmapTextureAtlas enemyBitmapTextureAtlas;
  private BitmapTextureAtlas mBossBitmapTextureAtlas;

  //TiledTextureRegions
  private TiledTextureRegion mSpriteTexture;
  private TiledTextureRegion mPlayerTextureRegion;
  private TiledTextureRegion mBossTextureRegion;

  //Camera
  private BoundCamera mBoundChaseCamera;
  int cameraWidth, cameraHeight;

  //Scene
  private Scene mMainScene;

  //Sounds and Music
  private Music mMusic;
  private Sound mJumpSound;
  private Sound mHitSound;
  private Sound mDeathSound;
  private Sound mWinSound;

  //Map Stuff
  private TMXTiledMap mTMXTiledMap;
  //Tiles for player collision detection
  private TMXTile leftTile;
  private TMXTile rightTile;
  private TMXTile aboveTile;
  private TMXTile belowTile;
  private TMXTile curTile;
  //Tiles for enemy collision detection
  private TMXTile leftETile;
  private TMXTile rightETile;
  private TMXTile aboveETile;
  private TMXTile belowETile;
  private TMXTile fallETile;
  private TMXTile curETile;

  //Enemies
  public Vector<Enemy> enList;
  public Enemy en1;
  //Player
  Player player;
  int startLocX,startLocY;
  AnimatedSprite playerSprite;

  int leftOffset, rightOffset, aboveOffset, belowOffset;
  int colNum;	

  int mapColumns, mapRows;

  public void initEnemies()
  {
	enList = new Vector<Enemy>();
    en1 = new Enemy(startLocX+256,startLocY-96, mBoundChaseCamera, mSpriteTexture,mMainScene, 150);
    enList.addElement(en1);
    en1 = new Enemy(startLocX+192, startLocY-32, mBoundChaseCamera, mSpriteTexture, mMainScene, 100);
    enList.addElement(en1);
    en1 = new Enemy(416, 768, mBoundChaseCamera, mSpriteTexture, mMainScene, 200);
    enList.addElement(en1);/*
    en1 = new Enemy(736, 736, mBoundChaseCamera, mSpriteTexture, mMainScene, 200);
    enList.addElement(en1);
    en1 = new Enemy(736, 864, mBoundChaseCamera, mSpriteTexture, mMainScene, 200);
    enList.addElement(en1);
    en1 = new Enemy(864, 864, mBoundChaseCamera, mSpriteTexture, mMainScene, 200);
    enList.addElement(en1);
    en1 = new Enemy(1024, 864, mBoundChaseCamera, mSpriteTexture, mMainScene, 200);
    enList.addElement(en1);
    en1 = new Enemy(1600, 800, mBoundChaseCamera, mSpriteTexture, mMainScene, 200);
    enList.addElement(en1);
    en1 = new Enemy(2240, 672, mBoundChaseCamera, mSpriteTexture, mMainScene, 200);
    enList.addElement(en1);
    en1 = new Enemy(2880, 736, mBoundChaseCamera, mSpriteTexture, mMainScene, 200);
    enList.addElement(en1);
    en1 = new Enemy(3200, 736, mBoundChaseCamera, mSpriteTexture, mMainScene, 200);
    enList.addElement(en1);
    en1 = new Enemy(4160, 800, mBoundChaseCamera, mSpriteTexture, mMainScene, 200);
    enList.addElement(en1);
    en1 = new Enemy(4880, 832, mBoundChaseCamera, mSpriteTexture, mMainScene, 200);
    enList.addElement(en1);
    en1 = new Enemy(5440, 896, mBoundChaseCamera, mSpriteTexture, mMainScene, 200);
    enList.addElement(en1);
    en1 = new Enemy(5278, 896, mBoundChaseCamera, mSpriteTexture, mMainScene, 200);
    enList.addElement(en1);
    en1 = new Enemy(5760, 896, mBoundChaseCamera, mSpriteTexture, mMainScene, 200);
    enList.addElement(en1);
    en1 = new Enemy(5760, 576, mBoundChaseCamera, mSpriteTexture, mMainScene, 200);
    enList.addElement(en1);
    en1 = new Boss(8000, 800, mBoundChaseCamera,mBossTextureRegion, mMainScene, 500);
    enList.addElement(en1);*/
    return;
  }

  public void initPlayer(int xi, int yi,  int mapWidth, int mapHeight, TiledTextureRegion texture)
  {
    player = new Player(xi, yi, mapWidth, mapHeight, texture);
    playerSprite = new AnimatedSprite(startLocX, startLocY, mPlayerTextureRegion);
    playerSprite.animate(new long[]{200, 200, 200}, 6, 8, true);

    return;
  }

  public void initOffsets(int left, int right, int above, int below)
  {
    leftOffset = 3 - (int)(playerSprite.getWidth() / 2);
    rightOffset = -3 + (int)(playerSprite.getWidth() / 2);
    aboveOffset = 10 - (int)(playerSprite.getHeight() / 2);
    belowOffset = -5 + (int)(playerSprite.getHeight() / 2);

    return;
  }

  @Override
  public void onLoadComplete() 
  {
    // TODO Auto-generated method stub

  }

  @Override
  public Engine onLoadEngine()
  {
    this.cameraWidth = getWindowManager().getDefaultDisplay().getWidth();
    this.cameraHeight = getWindowManager().getDefaultDisplay().getHeight();
    cameraWidth = 480;
    cameraHeight = 240;
    this.mBoundChaseCamera = new BoundCamera(0, 0, cameraWidth, cameraHeight);
    return new Engine(new EngineOptions(true, ScreenOrientation.LANDSCAPE, 
        new RatioResolutionPolicy(cameraWidth, cameraHeight), 
        this.mBoundChaseCamera).setNeedsMusic(true).setNeedsSound(true));
  }

  @Override
  public void onLoadResources()
  {
    //Textures
    this.mBitmapTextureAtlas = new BitmapTextureAtlas(256, 256, TextureOptions.NEAREST);
    this.enemyBitmapTextureAtlas = new BitmapTextureAtlas(256, 256, TextureOptions.NEAREST);
    this.mBossBitmapTextureAtlas = new BitmapTextureAtlas(512, 512, TextureOptions.NEAREST);
    BitmapTextureAtlasTextureRegionFactory.setAssetBasePath("gfx/");

    this.mSpriteTexture = BitmapTextureAtlasTextureRegionFactory.createTiledFromAsset(this.enemyBitmapTextureAtlas, this, "baseenemy.png", 0, 0, 6, 3);
    this.mPlayerTextureRegion = BitmapTextureAtlasTextureRegionFactory.createTiledFromAsset(this.mBitmapTextureAtlas, this, "player.png", 0, 0, 3, 4); // 72x128
    this.mBossTextureRegion = BitmapTextureAtlasTextureRegionFactory.createTiledFromAsset(this.mBossBitmapTextureAtlas, this, "dedede.png", 0, 0,5,2);

    mEngine.getTextureManager().loadTexture(mBitmapTextureAtlas);
    mEngine.getTextureManager().loadTexture(enemyBitmapTextureAtlas);
    mEngine.getTextureManager().loadTexture(mBossBitmapTextureAtlas);

    //Music
    MusicFactory.setAssetBasePath("mfx/");
    SoundFactory.setAssetBasePath("mfx/");

    try {
      this.mMusic = MusicFactory.createMusicFromAsset(this.mEngine.getMusicManager(), this, "spacepirates.mp3");
      this.mMusic.setLooping(true);
    } catch (final IOException e) {
      Debug.e("Error", e);
    }

    //Sound Jump
    try {
      this.mJumpSound = SoundFactory.createSoundFromAsset(this.mEngine.getSoundManager(), this, "jumpsound.mp3");
    } catch (final IOException e) {
      Debug.e("Error", e);
    }

    //Sound Punch
    try {
      this.mHitSound = SoundFactory.createSoundFromAsset(this.mEngine.getSoundManager(), this, "Punch_HD.mp3");
    } catch (final IOException e) {
      Debug.e("Error", e);
    }

    //Sound Death
    try {
      this.mDeathSound = SoundFactory.createSoundFromAsset(this.mEngine.getSoundManager(), this, "Game_Over.mp3");
    } catch (final IOException e) {
      Debug.e("Error", e);
    }

    //Sound Win
    try {
      this.mWinSound = SoundFactory.createSoundFromAsset(this.mEngine.getSoundManager(), this, "Win.mp3");
    } catch (final IOException e) {
      Debug.e("Error", e);
    }

  }

  @Override
  public Scene onLoadScene() {

    Log.v("EECS285 PROJECT4", "onLoadScene");

    mEngine.registerUpdateHandler(new FPSLogger());
    mMainScene = new Scene();
    mMainScene.setBackground(new ColorBackground(0.89019f, 0.65882f, 0.41176f));
    mMainScene.setOnSceneTouchListener(this);
    this.mMusic.play();
    this.mMusic.setVolume(0.01f);
    
    this.startLocX = 50;
    this.startLocY = 100;
    
    try {

      final TMXLoader tmxLoader = new TMXLoader(this, this.mEngine.getTextureManager(), TextureOptions.NEAREST, new ITMXTilePropertiesListener()
      {
        @Override
        public void onTMXTileWithPropertiesCreated(final TMXTiledMap pTMXTiledMap, final TMXLayer pTMXLayer, final TMXTile pTMXTile, final TMXProperties<TMXTileProperty> pTMXTileProperties)
        {
          if(pTMXTileProperties.containsTMXProperty("solid", "true"))
          {
            SampleGameActivity.this.colNum++;
            //Log.v("EECS285 PROJECT4", "Found Collision Tile");
          }
          if(pTMXTileProperties.containsTMXProperty("start", "true")) 
          {
            SampleGameActivity.this.startLocX = 32*pTMXTile.getTileColumn();
            SampleGameActivity.this.startLocY = 32*pTMXTile.getTileRow();
            Log.v("EECS285 PROJECT4", "Found Start Location (x,y): (" 
                + SampleGameActivity.this.startLocX + ", " + SampleGameActivity.this.startLocY + ")");
          }
        }
      });
      this.mTMXTiledMap = tmxLoader.loadFromAsset(this, "tmx/largeGameMap.tmx");
    }
    catch (final TMXLoadException tmxle)
    {
      Debug.e(tmxle);
      Log.v("EECS285 PROJECT4", "Problem Loading");
    }
    Log.v("EECS285 PROJECT4", "Collision #: " +this.colNum);
    Log.v("EECS285 PROJECT4", "# of Layers: " +mTMXTiledMap.getTMXLayers().toArray().length);
    final TMXLayer deepBackground = this.mTMXTiledMap.getTMXLayers().get(0);
    final TMXLayer background = this.mTMXTiledMap.getTMXLayers().get(1);
    final TMXLayer foreground = this.mTMXTiledMap.getTMXLayers().get(2);
    final TMXLayer collision = this.mTMXTiledMap.getTMXLayers().get(3);
    mapColumns = mTMXTiledMap.getTileColumns();
    mapRows = mTMXTiledMap.getTileRows();
    mMainScene.attachChild(deepBackground);
    mMainScene.attachChild(background);
    mMainScene.attachChild(foreground);

    // Make the camera not exceed the bounds of the TMXEntity. 
    this.mBoundChaseCamera.setBounds(0, background.getWidth(), 0, background.getHeight());
    this.mBoundChaseCamera.setBoundsEnabled(true);
    //mapWidth should be a constant so we are setting its value in our Definitions
    Definitions.mapWidth = (int)background.getWidth();
    Definitions.mapHeight = (int)background.getHeight();
    
    initEnemies();
    initPlayer(startLocX, startLocY, Definitions.mapWidth, Definitions.mapHeight, mPlayerTextureRegion);
    Log.v("EECS285 PROJECT4", "Generating init Player");
    mBoundChaseCamera.setChaseEntity(playerSprite);
    mMainScene.attachChild(playerSprite);
    initOffsets(leftOffset, rightOffset, aboveOffset, belowOffset); //set offsets

    this.mMainScene.registerUpdateHandler(new IUpdateHandler()
    {
      public void onUpdate(float pSecondsElapsed)
      {
        if(!player.isAlive())
        {
          mDeathSound.play();
          Intent n = new Intent(getApplicationContext(), LoseActivity.class);
          startActivity(n);
          //finish();
        }
        for(int i = 0; i < enList.size(); i++)
        {
          if(enList.get(i).isBoss())
          {
            if(!enList.get(i).isAlive())
            {
              mWinSound.play();
              Intent n = new Intent(getApplicationContext(), WinActivity.class);
              startActivity(n);
              //finish();
            }
          }    	
          if(enList.get(i).isHitSoundFlag()) 
          {
            mHitSound.play();
            enList.get(i).setHitSoundFlag(false);
          }
          if(!enList.get(i).isAlive())
          {
            enList.remove(i);
          }
        }

        if(player.jumpSoundFlag)
        {
          mJumpSound.play();
          player.jumpSoundFlag = false;
        }
        //Log.v("EECS285 PROJECT4", "seconds elapsed: "+pSecondsElapsed);
        player.updateTime(pSecondsElapsed);

        curTile = collision.getTMXTileAt(player.getpCol().x, player.getpCol().y);
        leftTile = curTile;
        rightTile = curTile;
        aboveTile = curTile;
        belowTile = curTile;
        //Log.v("EECS285 PROJECT4", "curTile Id: " +curTile.getGlobalTileID() +"; (x,y): (" +curTile.getTileColumn() +","+curTile.getTileRow() + ")");

        if (curTile.getTileColumn() != 0) {
          leftTile = collision.getTMXTileAt(player.getpCol().x + leftOffset, player.getpCol().y);
          //Log.v("EECS285 PROJECT4", "leftTile Id: " +leftTile.getGlobalTileID() +"; (x,y): (" +leftTile.getTileColumn() +","+leftTile.getTileRow() + ")");
        }

        if (curTile.getTileColumn() != (mapColumns - 1)) {
          rightTile = collision.getTMXTileAt(player.getpCol().x + rightOffset, player.getpCol().y);
          //Log.v("EECS285 PROJECT4", "rightTile Id: " +rightTile.getGlobalTileID() +"; (x,y): (" +rightTile.getTileColumn() +","+rightTile.getTileRow() + ")");
        }

        if (curTile.getTileRow() != 0) {
          aboveTile = collision.getTMXTileAt(player.getpCol().x, player.getpCol().y + aboveOffset);
          //Log.v("EECS285 PROJECT4", "aboveTile Id: " +aboveTile.getGlobalTileID() +"; (x,y): (" +aboveTile.getTileColumn() +","+aboveTile.getTileRow() + ")");
        }

        if (curTile.getTileRow() != (mapRows - 1)) {
          belowTile = collision.getTMXTileAt(player.getpCol().x, player.getpCol().y + belowOffset);
          //Log.v("EECS285 PROJECT4", "belowTile Id: " +belowTile.getGlobalTileID() +"; (x,y): (" +belowTile.getTileColumn() +","+belowTile.getTileRow() + ")");
        }

        player.update(playerSprite, leftTile, rightTile, aboveTile, belowTile, enList);

        for (int i = 0; i < enList.size(); i++) {

          curETile = collision.getTMXTileAt(enList.elementAt(i).getCoor().x, enList.elementAt(i).getCoor().y);
          leftETile = curETile;
          rightETile = curETile;
          aboveETile = curETile;
          belowETile = curETile;
          fallETile = curETile;

          if (curTile.getTileColumn() != 0) {
            leftETile = collision.getTMXTileAt(enList.elementAt(i).getCircle().x+leftOffset,enList.elementAt(i).getCircle().y);
          }
          if (curTile.getTileColumn() != (mapColumns - 1)) {
            rightETile = collision.getTMXTileAt(enList.elementAt(i).getCircle().x+rightOffset,enList.elementAt(i).getCircle().y);
          }	
          if (curTile.getTileRow() != 0) {
            aboveETile = collision.getTMXTileAt(enList.elementAt(i).getCircle().x,enList.elementAt(i).getCircle().y+aboveOffset);
          }
          if (curTile.getTileRow() != (mapRows -1)) {
            belowETile = collision.getTMXTileAt(enList.elementAt(i).getCircle().x,enList.elementAt(i).getCircle().y+belowOffset);
          }
          if (enList.elementAt(i).getDir() == Direction.LEFT && curTile.getTileColumn() != 0 && curTile.getTileRow() != (mapRows -1)) {
            fallETile = collision.getTMXTileAt(enList.elementAt(i).getCircle().x+leftOffset, enList.elementAt(i).getCircle().y+belowOffset);
          }
          if (enList.elementAt(i).getDir() == Direction.RIGHT && curTile.getTileColumn() != (mapColumns -1) && curTile.getTileRow() != (mapRows-1)) {
            fallETile = collision.getTMXTileAt(enList.elementAt(i).getCircle().x+rightOffset, enList.elementAt(i).getCircle().y+belowOffset);
          }

          enList.elementAt(i).enemyUpdate(leftETile, rightETile, aboveETile, belowETile, fallETile);
          enList.elementAt(i).updateAnimation();
        }

        if(player.changedDirection()) {
          player.updateAnimation(playerSprite);
          //Log.v("EECS285 PROJECT4", "Updating Animation");
        }
        player.changeOldFacing(player.getFacing());
      }

      public void reset() {
        // TODO Auto-generated method stub
      }
    });
	
    return mMainScene;

  }

  @Override
  public boolean onSceneTouchEvent(final Scene pScene, final TouchEvent pSceneTouchEvent) {

    if(pSceneTouchEvent.isActionDown()) {
      //Log.v("EECS285 PROJECT4", "Player Jumped!!");
      mBoundChaseCamera.convertSceneToCameraSceneTouchEvent(pSceneTouchEvent);
      //float cameraX = pSceneTouchEvent.getX()%mBoundChaseCamera.getWidth();
      //float cameraY = pSceneTouchEvent.getY()%mBoundChaseCamera.getHeight();
      float cameraX = pSceneTouchEvent.getX();
      float cameraY = pSceneTouchEvent.getY();
      if((cameraX < mBoundChaseCamera.getWidth()/8) && (cameraY > mBoundChaseCamera.getHeight()*(3/4))) {
        if(player.isJump() == true || player.isFall() == true) {
          return false;
        }
        else {
          player.jump();
          return true;
        }
      }
      else {
        return false;
      }
    }		
    else {
      return false;
    }
  }

  @Override
  public void onAccelerometerChanged(final AccelerometerData pAccelerometerData) {
	  
    if (pAccelerometerData.getX() > 1.5) {
      player.changeFacing("RIGHT");
    }
    else if (pAccelerometerData.getX() < -1.5){
      player.changeFacing("LEFT");
    }
    else {
      player.changeFacing("FORWARD");
    }
    
  }

  @Override
  public void onResumeGame() {
    super.onResumeGame();

    this.enableAccelerometerSensor(this);
    this.mMusic.play();
    this.mMusic.setVolume(0.01f);
  }

  @Override
  public void onPauseGame() {
    super.onPauseGame();

    this.disableAccelerometerSensor();
    this.mMusic.pause();
  }

}
